﻿using System;

namespace MutsiEngine
{
    public struct Matrix4x4
    {
        public double[] Matrix;

        public static double[] Identity{
            get{return new double[16]{1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0};}
        }

        public static double[] CreateLookDirection(Vector3 position, Vector3 Direction, Vector3 worldUp)
        {
            double[] matrix = new double[16];

            Direction.Normalize();
            worldUp.Normalize();

            Vector3 right = Vector3.CrossProduct(Direction, worldUp);
            Vector3 up = Vector3.CrossProduct(right, Direction);

            //Set the matrix
            matrix[0] = -right.X;
            matrix[1] = right.Y;
            matrix[2] = right.Z;
            matrix[3] = 0.0;
            matrix[4] = up.X;
            matrix[5] = up.Y;
            matrix[6] = up.Z;
            matrix[7] = 0.0;
            matrix[8] = Direction.X;
            matrix[9] = Direction.Y;
            matrix[10] = -Direction.Z;
            matrix[11] = 0;
            matrix[12] = 0;
            matrix[13] = 0;
            matrix[14] = 0;
            matrix[15] = 1.0;

            return matrix;
        }


        public static double[] CreateLookAt(Vector3 position, Vector3 target, Vector3 worldUp)
        {
            double[] matrix = new double[16];

            Vector3 forward = new Vector3(target.X - position.X, target.Y - position.Y, target.Z - position.Z);

            forward.Normalize();
            worldUp.Normalize();

            Vector3 right = Vector3.CrossProduct(forward, worldUp);
            Vector3 up = Vector3.CrossProduct(right, forward);

            //Set the matrix
            matrix[0] = -right.X;
            matrix[1] = right.Y;
            matrix[2] = right.Z;
            matrix[3] = 0.0;
            matrix[4] = up.X;
            matrix[5] = up.Y;
            matrix[6] = up.Z;
            matrix[7] = 0.0;
            matrix[8] = forward.X;
            matrix[9] = forward.Y;
            matrix[10] = forward.Z;
            matrix[11] = 0;
            matrix[12] = 0;
            matrix[13] = 0;
            matrix[14] = 0;
            matrix[15] = 1.0;

            return matrix;
        }

        public static double[] CreatePerspectiveFieldOfView(float fovyInDegrees, float aspectRatio, float znear, float zfar)
        {
            double[] matrix = new double[16];
            float ymax, xmax;
            ymax = znear * (float)Math.Tan(fovyInDegrees * Math.PI / 360.0);
            xmax = ymax * aspectRatio;

            float zNear2, xMax2, yMax2, zRange;
            zNear2 = 2.0f * znear;
            xMax2 = xmax + xmax;
            yMax2 = ymax + ymax;
            zRange = zfar - znear;

            //Set the matrix
            matrix[0] = zNear2 / xMax2;
            matrix[1] = 0.0;
            matrix[2] = 0.0;
            matrix[3] = 0.0;
            matrix[4] = 0.0;
            matrix[5] = zNear2 / yMax2;
            matrix[6] = 0.0f;
            matrix[7] = 0.0f;
            matrix[8] = (xmax + -xmax) / xMax2;
            matrix[9] = (ymax + -ymax) / yMax2;
            matrix[10] = (-zfar - znear) / zRange;
            matrix[11] = -1.0;
            matrix[12] = 0.0;
            matrix[13] = 0.0;
            matrix[14] = (-zNear2 * zfar) / zRange;
            matrix[15] = 0.0;

            return matrix;
        }
    }
}